package com.ss.gReader;

import com.ss.gReader.view.controller.SsReader;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.When;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.input.KeyCombination;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class App extends Application {

    private static final Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());

    private boolean tmFlag = false;
    private Stage normalStage;
    private Stage transparentStage;
    private Scene scene;


    SsReader reader;

    public final static double minOpacity = 0.3;
    private ObjectBinding<Insets> insets;


    @Override
    public void start(Stage stage) throws IOException {
        initUI(stage);
        hotKey();

        stage.show();

        reader.prefWidthProperty().bind(reader.widthProperty());
        reader.prefHeightProperty().bind(reader.heightProperty());

        globalKey();
    }


    private void globalKey() {
        logger.setLevel(Level.OFF);
        normalStage.setOnCloseRequest(event -> {
            try {
                GlobalScreen.unregisterNativeHook();
            } catch (NativeHookException e) {
                e.printStackTrace();
            }
        });
        transparentStage.setOnCloseRequest(event -> {
            try {
                GlobalScreen.unregisterNativeHook();
            } catch (NativeHookException e) {
                e.printStackTrace();
            }
        });
        try {
            GlobalScreen.registerNativeHook();
        } catch (NativeHookException ex) {
            ex.printStackTrace();
        }
        GlobalScreen.addNativeKeyListener(new NativeKeyListener() {
            @Override
            public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) {

            }

            @Override
            public void nativeKeyPressed(NativeKeyEvent nativeKeyEvent) {
                SsReader.instance.keyPressed(nativeKeyEvent);
            }

            @Override
            public void nativeKeyReleased(NativeKeyEvent nativeKeyEvent) {
                SsReader.instance.keyReleased(nativeKeyEvent);
            }
        });
    }

    private void initUI(Stage stage) {
        this.normalStage = stage;
        reader = SsReader.instance;
        Scene scene = new Scene(reader);
        this.scene = scene;
        this.scene.setFill(null);
        stage.opacityProperty().bind(new When(reader.backOpacityPropertyProperty().lessThan(minOpacity)).then(minOpacity).otherwise(reader.backOpacityPropertyProperty()));
        stage.setScene(scene);

        Stage transparentStage = new Stage();
        transparentStage.initStyle(StageStyle.TRANSPARENT);
        this.transparentStage = transparentStage;

        reader.menuBar.heightProperty().addListener((observable, oldValue, newValue) ->
                insets = Bindings.createObjectBinding(() ->
                new Insets(scene.getY() + newValue.doubleValue(),
                        normalStage.getWidth() - scene.getWidth() - scene.getX(),
                        normalStage.getHeight() - reader.getHeight() - scene.getY(),
                        scene.getX())
        ));

    }

    private void hotKey() {
        KeyCombination kc = KeyCombination.valueOf("o");
        KeyCombination before = KeyCombination.valueOf("j");
        KeyCombination next = KeyCombination.valueOf("l");
        scene.getAccelerators().put(kc, this::changeTm);
        scene.getAccelerators().put(before, reader::beforePage);
        scene.getAccelerators().put(next, reader::nextPage);
    }

    private void changeThing(Stage stage1, Stage stage2, int fh) {
        stage1.setX(stage2.getX() + fh * insets.get().getLeft());
        stage1.setY(stage2.getY() + fh * insets.get().getTop());
        stage1.setScene(this.scene);
        stage1.show();
        stage2.hide();
    }

    private void changeTm() {
        tmFlag = !tmFlag;
        reader.changeState(tmFlag);
        Platform.runLater(() -> {
            if (tmFlag) {
                changeThing(transparentStage, normalStage, 1);
            } else {
                changeThing(normalStage, transparentStage, -1);
            }
        });

    }
}
